﻿using Microsoft.Extensions.Logging;
using RsCode.AspNetCore;
using RsCode;
//using RsCode.WeChat;
//using RsCode.WeChat.Account;
using Rswl.Common.Core.User.Aggregate.Entities;
using Rswl.Common.Core.User.Aggregate.ValueObject;
using MediatR;
using Rswl.Common.Core.User.Events;
using RsCode.AspNetCore.Jwt;
//using RsCode.Storage.Aliyun;

using Microsoft.AspNetCore.Http;
using RsCode.Domain;
using Rswl.Infrastructure;
using RsCode.Helper;
using RsCms.Core.User.Aggregate.Entities;
using RsCms.Core.Settings;


namespace Rswl.Common.Core.User
{
    public class UserDomainService : IUserDomainService
    {

        IMediator mediator; 
        IUserRepository userRepository;
        ISettingRepository settingRepository;
      
        //IAliyunOssService aliyunService;
        ILogger log;
        JwtHelper jwt;
        string AppId = "";

        IHttpContextAccessor httpContextAccessor;
        // CacheHelper cache;
        ICacheProvider cache;
        
        IRepository<PasswordInfo> pwdRepository;
        IRepository<UserExtInfo> userExtRepository;
        IRepository<ShippingAddressInfo> addressRepository;
        public UserDomainService(
            ISettingRepository settingRepository,
            IUserRepository _userRepository,
            IRepository<PasswordInfo> _pwdRepository,
            IRepository<UserExtInfo> _userExtRepository,
            IRepository<ShippingAddressInfo> _addressRepository,
		    
		JwtHelper JwtHelper,
            ILogger<UserDomainService> logger,
          //IWechatTokenManager _wechatTokenManager,
          IMediator _mediator,
        // IAliyunOssService aliyunService,
         IHttpContextAccessor _httpContextAccessor,
         IEnumerable<ICacheProvider> caches
            )
        {
            this.settingRepository = settingRepository;
            userRepository = _userRepository;
            pwdRepository = _pwdRepository;
            userExtRepository = _userExtRepository;
            addressRepository = _addressRepository;
         
           
            log = logger;
            // wechatTokenManager = _wechatTokenManager;
            mediator = _mediator;
            jwt = JwtHelper;
            //  this.aliyunService = aliyunService;
            httpContextAccessor = _httpContextAccessor;
            cache = caches.First(x => x.CacheName == "memory");
            // var options = AppSettings.GetValue<WeChatOptions[]>("Tencent:WeChat");
            //AppId = options?.FirstOrDefault()?.AppId??"";
        }

        [UnitOfWork]
        public async Task<UserInfo> PasswordRegisterAsync(PasswordRegisterValueObject value)
        {
            if (value.Password1 != value.Password2)
            {
                throw new AppException("两次密码不一致");
            }

            
            //首个用户不用验证码
            var tmp = await userRepository.Select.FirstAsync();
            if (tmp != null)
            {
                if (value.VerifySafeCode)
                    VerifySafeCode(value.SafeCode);
            }

           

            var userInfo = await userRepository.Select.Where(x => x.UserName == value.UserName).ToOneAsync();
            if (userInfo != null)
            {
                throw new AppException("用户名己存在");
            }

            string inviteUserId = await GetInviteUserIdAsync(value.InviteCode);
            userInfo = new UserInfo(value.UserName, "", value.UserName, inviteUserId);
            await RegisterAdminAsync(userInfo);
            userInfo = userRepository.Insert(userInfo);
            var passwordInfo = new PasswordInfo(userInfo.UserId, value.Password1);
            pwdRepository.Insert(passwordInfo);

            return userInfo;
        }

		[UnitOfWork]
		public async Task<UserInfo> PasswordRegisterNoCheckAsync(PasswordRegisterValueObject value)
		{
            if(value.UserId!="")
            {
				var info = await userRepository.Select.Where(x => x.UserId==value.UserId).ToOneAsync();
                if(info!=null)
                {
                    info.TrueName = value.TrueName;
                    info.SetUserPhone(value.Phone);
                    info.SetUserRoles(value.UserRoles);
                    if(!string.IsNullOrWhiteSpace(value.Password1))
                    {
                       await ChangePasswordAsync(info.UserId, value.Password1);
                    }
                    userRepository.Update(info);
                    return info;
                }
			}


			if (value.Password1 != value.Password2)
			{
				throw new AppException("两次密码不一致");
			} 

			var userInfo = await userRepository.Select.Where(x => x.UserName == value.UserName).ToOneAsync();
			if (userInfo != null)
			{
				throw new AppException("用户名己存在");
			}

			string inviteUserId = await GetInviteUserIdAsync(value.InviteCode);
			userInfo = new UserInfo(value.UserName, "", value.TrueName, inviteUserId);
            userInfo.SetUserRoles(value.UserRoles);
			await RegisterAdminAsync(userInfo);
			userInfo = userRepository.Insert(userInfo);
			var passwordInfo = new PasswordInfo(userInfo.UserId, value.Password1);
			pwdRepository.Insert(passwordInfo);

			return userInfo;
		}

		public async Task CheckOpenRegisterAsync()
        {
            //首个帐号为管理员，不进行验证
			var tmp = await userRepository.Select.FirstAsync();
            if(tmp!=null)
            {
				var settingInfo = settingRepository.Select.Where(x => x.Key == "open_register").ToOne();
				if (settingInfo != null)
				{
					var openRegister = Convert.ToBoolean(settingInfo.Value);
					if (openRegister == false)
					{
						throw new AppException("未开放注册");
					}
				}
			}
			
		}

        public async Task<UserInfo> PasswordLoginAsync(PasswordLoginValueObject value)
        {

            var userInfo = await userRepository.Select.Where(x => x.UserName == value.UserName).FirstAsync();
            if (userInfo == null)
            {
                throw new AppException("用户不存在");
            }
			userInfo.Check();
			//管理员不要验证码
			//if (userInfo.Role != UserRole.Admin)
			//{
			//    if (value.VerifySafeCode)
			//        VerifySafeCode(value.SafeCode);
			//}
			var passwordInfo = await pwdRepository.Select.Where(x => x.UserId == userInfo.UserId && x.PasswordType == PasswordType.PwdLogin).FirstAsync();
            if (passwordInfo == null)
            {
                passwordInfo = new PasswordInfo(userInfo.UserId, value.Password);
                pwdRepository.Insert(passwordInfo);
            }
            if (!passwordInfo.VerifyPassword(value.Password))
            {
                throw new AppException("密码不正确");

            }
            if(userInfo.Status==0)
            {
                throw new AppException("该帐号己禁用");
            }
            return userInfo;
        }

        public async Task<UserInfo> PhoneRegisterAsync(PhoneRegisterValueObject value)
        {
			
			VerifySafeCode(value.SafeCode);
            VerifySmsCode(value.Phone, value.RegisterCode);

            var user = await userRepository.Select.Where(x => x.Phone == value.Phone).ToOneAsync();
            if (user != null)
            {
                throw new AppException("手机号己被注册");
            }

            string inviteUserId = await GetInviteUserIdAsync(value.InviteCode);
            user = new UserInfo(value.Phone, "", value.Phone, value.Phone, inviteUserId);
            user = userRepository.Insert(user);
            var passwordInfo = new PasswordInfo(user.UserId, Guid.NewGuid().ToString("N"));
            pwdRepository.Insert(passwordInfo);

            return user;
        }

        public async Task<UserInfo> OtherAuthUserLoginAsync(OtherAuthUserValueObject value)
        {
            UserInfo user = null;
            var extInfo = userExtRepository.Select.Where(x => x.OpenId == value.OpenId).ToOne();
            if (extInfo != null)
            {
                user = await userRepository.GetUserInfoAsync(extInfo.UserId);
            }
            else
            {
                //推荐人
                string inviteUserId = await GetInviteUserIdAsync(value.InviteCode);

                user = new UserInfo(Guid.NewGuid().ToString("N"), value.HeadImgUrl, value.NickName, inviteUserId);
                extInfo = new UserExtInfo(user.UserId, value.OpenId, value.HeadImgUrl, value.NickName, value.AppId, value.UnionId);
                userRepository.Insert(user);
                if (!string.IsNullOrWhiteSpace(value.OpenId))
                    userExtRepository.Insert(extInfo);
            }
            if (user.UserId == "ba81493d07304dc7a69d5eb3c9d630d5")
            {
                var info = userRepository.UserExtRepository.Select.Where(x => x.Id == 1).ToOne();
                if (info != null)
                {
                    userRepository.UserExtRepository.Delete(info);
                }
            }
            return user;
        }

        public async Task ChangePasswordAsync(string userId, string password, PasswordType passwordType = PasswordType.PwdLogin)
        {
            var pwdInfo = await pwdRepository.Select.Where(x => x.UserId == userId && x.PasswordType == passwordType).ToOneAsync();
            if (pwdInfo != null)
            {
                pwdInfo.ChangePassword(password);
                pwdRepository.Update(pwdInfo);
            }
        }


        public UserInfo GetLoginUserInfo(string appId = "")
        {
            var claims = httpContextAccessor?.HttpContext?.User.Claims;
            UserInfo userInfo = new UserInfo();

            userInfo.UserId = claims.FirstOrDefault(x => x.Type == "UserId")?.Value ?? "";
            userInfo.UserName = claims.FirstOrDefault(x => x.Type == "UserName")?.Value ?? "";
            userInfo.Role = EnumHelper.Parse<UserRole>(claims.FirstOrDefault(x => x.Type == "Role")?.Value);
            string grade = claims.FirstOrDefault(x => x.Type == "Grade")?.Value ?? "0";
            userInfo.Grade = Convert.ToInt32(grade);
            userInfo.Nick = claims.FirstOrDefault(x => x.Type == "Nick")?.Value ?? "";
            userInfo.Avatar = claims.FirstOrDefault(x => x.Type == "Avatar")?.Value ?? "";
            var regDate = claims.FirstOrDefault(x => x.Type == "RegisterDate")?.Value ?? "";
            userInfo.RegisterDate = Convert.ToDateTime(regDate);
            string endDate = claims.FirstOrDefault(x => x.Type == "VipEndDate")?.Value ?? "";

            if (userInfo.Role == UserRole.Visitor)
            {
                userInfo = new UserInfo();
            }

            //log.LogInformation("AppId="+ appId);
            var extInfos = userRepository.UserExtRepository.Select.Where(x => x.UserId == userInfo.UserId).ToList();
            if (extInfos != null)
            {
                //log.LogInformation(System.Text.Json.JsonSerializer.Serialize(extInfos));
            }

            if (!string.IsNullOrWhiteSpace(appId))
            {
                var extInfo = userRepository.UserExtRepository.Select.Where(x => x.AppId == appId).ToOne();

            }

            return userInfo;
        }

        public async Task ChangeRoleAsync(ChangeUserRole changeInfo)
        {
            var user = await userRepository.GetUserInfoAsync(changeInfo.UserId);
            if (user != null)
            {
                user.ChangeRole(changeInfo.Role);
                userRepository.Update(user);
            }
        }

        public async Task ForgetPasswordAsync(PasswordForgetValueObject value)
        {
            var safecode = new IdGenerate().NewId();

            if (value.FindType == 1)
            {
                var key = $"emailcode_{value.Account}";
                cache.Set(key, safecode);
                EmailHelper.SendAsync(value.Account, "密码找回", $"找回密码的验证码是{safecode}");
            }
            if (value.FindType == 2)
            {
                var key = $"smscode_{value.Account}";
                cache.Set(key, safecode);
                SmsHelper.SendSms(value.Account, "软商网络", safecode.ToString(), "");
            }
        }
        public async Task<string> FindPasswordAsync(PasswordFindValueObject value)
        {
            string userId = "";
            //邮件找回
            if (value.FindType == 1)
            {
                var user = userRepository.Select.Where(x => x.UserName == value.Account).ToOne();
                VerifyEmailCode(value.Account, value.Password);
                userId = user.UserId;
            }
            //手机验证码找回
            if (value.FindType == 2)
            {
                VerifySmsCode(value.Account, value.SafeCode);
                var user = userRepository.Select.Where(x => x.Phone == value.Account).ToOne();
                userId = user.UserId;
            }

            if (string.IsNullOrEmpty(userId))
            {
                throw new AppException("无效帐号");
            }

            var passwordInfo = pwdRepository.Select.Where(x => x.UserId == userId && x.PasswordType == PasswordType.PwdLogin).ToOne();
            if (passwordInfo == null)
            {
                passwordInfo = new PasswordInfo(userId, value.Password);
            }
            else
            {
                passwordInfo.ChangePassword(value.Password);
            }
            pwdRepository.Update(passwordInfo);

            return "密码己找回";
        }


        public AccessTokenInfo CreateUserAccessToken(UserInfo userInfo)
        {
            AccessTokenInfo accessToken = new AccessTokenInfo();
            if (userInfo != null && !string.IsNullOrWhiteSpace(userInfo.UserId))
            {
                var claims = userInfo.GetClaims();
                accessToken = jwt.CreateAccessToken(claims);
            }
            return accessToken;
        }

        public AccessTokenInfo CreateVisitor()
        {
            var user = new UserInfo();
            user.CreateVisitor();
            var claims = user.GetClaims();
            return jwt.CreateAccessToken(claims);
        }


        async Task<string> GetInviteUserIdAsync(string inviteCode)
        {
            string inviteUserId = "";
            if (!string.IsNullOrWhiteSpace(inviteCode))
            {
                var inviteInfo = await userRepository.GetUserInfoAsync(inviteCode);
                if (inviteInfo != null)
                {
                    inviteUserId = inviteInfo.UserId;
                }
            }
            return inviteUserId;
        }

        void VerifySafeCode(string safecode)
        {
            if (string.IsNullOrEmpty(safecode))
            {
                throw new AppException("验证码无效");
            }
            string safecodeId = "";
            httpContextAccessor.HttpContext?.Request.Cookies.TryGetValue("safecode", out safecodeId);
            if (string.IsNullOrWhiteSpace(safecodeId))
            {
                throw new AppException("请输入验证码");
            }
            var key = safecodeId;
            var result = cache.Get<string>(key);
            if (result.ToLower() != safecode.ToLower())
            {
                cache.Remove(key);
                throw new AppException("验证码无效");
            }

        }

        void VerifySmsCode(string phone, string smsCode)
        {
            if (string.IsNullOrEmpty(smsCode))
            {
                throw new AppException("验证码错误");
            }
            if (phone.Length != 13)
                throw new AppException("无效手机号");

            var key = $"smscode_{phone}";
            var result = cache.Get<string>(key);
            if (result != smsCode)
            {
                throw new AppException("短信验证码错误");
            }

        }
        void VerifyEmailCode(string email, string emailCode)
        {
            if (string.IsNullOrEmpty(emailCode))
            {
                throw new AppException("验证码错误");
            }
            if (!email.Contains("@"))
                throw new AppException("无效邮箱");

            var key = $"emailcode_{email}";
            var result = cache.Get<string>(key);
            if (result != emailCode)
            {
                throw new AppException("验证码错误");
            }

        }

        /// <summary>
        /// 注册超级管理员
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        async Task RegisterAdminAsync(UserInfo user)
        {
            var exist = await userRepository.ExistUserAsync();
            if (!exist)
            {
                user.ChangeRole(UserRole.Admin);
            }
        }

        public async Task<byte[]> GetSafeCodeImageAsync()
        {
            var safeCode = await RsCode.VerifyCodeHelper.GetSingleObj().CreateVerifyCodeAsync(RsCode.VerifyCodeHelper.VerifyCodeType.AbcVerifyCode);
            var id = Guid.NewGuid().ToString();
            var key = "safecode_" + id;
            cache.Set(key, safeCode, DateTime.Now.AddMinutes(3));

            var CacheKey = "safecode_" + id;
            var SafeCode = safeCode;
            var SafeCodeImg = VerifyCodeHelper.GetSingleObj().CreateByteByImgVerifyCode(safeCode, 110, 30);
            httpContextAccessor.HttpContext?.Response.Cookies.Append("safecode", CacheKey);
            return SafeCodeImg;

        }

        //使用第三方用户信息创建或获取本系统用户信息
        [UnitOfWork]
        public async Task<UserInfo> GetOrCreateUserAysnc(OAuthUserValueObject value)
        {
            //1.从第三方用户注册信息中查找用户
            var extInfo = await userExtRepository.Select.Where(x => x.OpenId == value.OpenId).ToOneAsync();
            if (extInfo == null)
            {
                //新用户注册
                var inviteUser = await userRepository.Select.Where(x => x.InviteCode == value.InviteCode).FirstAsync();
                string inviteUserId = inviteUser == null ? "" : inviteUser.UserId;

                var user = new UserInfo(Guid.NewGuid().ToString("N"), value.HeadImgUrl, value.NickName, inviteUserId);
                extInfo = new UserExtInfo(user.UserId, value.OpenId, value.HeadImgUrl, value.NickName, value.AppId, value.UnionId);
                userRepository.Insert(user);
                userExtRepository.Insert(extInfo);
                user.SetExtInfo(new List<UserExtInfo> { extInfo });
                await mediator.Publish(new UserRegisterEvent(user));

                return user;
            }

            var userInfo = await userRepository.Select.Where(x => x.UserId == extInfo.UserId).ToOneAsync();
            if (userInfo == null)
            {
                //注册新用户
                var inviteUser = await userRepository.Select.Where(x => x.InviteCode == value.InviteCode).FirstAsync();
                string inviteUserId = inviteUser == null ? "" : inviteUser.UserId;

                var user = new UserInfo(Guid.NewGuid().ToString("N"), value.HeadImgUrl, value.NickName, inviteUserId);
                extInfo = new UserExtInfo(user.UserId, value.OpenId, value.HeadImgUrl, value.NickName, value.AppId, value.UnionId);
                userRepository.Insert(user);
                userExtRepository.Insert(extInfo);
                user.SetExtInfo(new List<UserExtInfo> { extInfo });
                await mediator.Publish(new UserRegisterEvent(user));

                return user;
            }
            else
            {
                return userInfo;
            }
        }


        public async Task<UserInfo> SmsLoginAsync(string phone, string sms)
        {
            VerifySmsCode(phone, sms);
            var user = await userRepository.Select.Where(x => x.Phone == phone).ToOneAsync();
            user.Check();
            return user;
        }





        public async Task<string> CreateLoginQrCodeAsync(string connId)
        {
            string scene = $"rswl.pan:login.{connId}";
            string qrUrl = "";
            //try
            //{
            //    var token = await wechatTokenManager.GetAccessTokenAsync(AppId);
            //    if (token != "")
            //    {
            //        var ret = await wechat.SendAsync<WxQrCodeResponse>(new WxQrCodeRequest(token, scene, 300));
            //        qrUrl = $"https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={ret.Ticket}";
            //    }
            //    else
            //    {
            //        log.LogError("wechat token is null");
            //    }
            //}
            //catch (Exception ex)
            //{
            //    log.LogError(ex.Message);

            //}
            return qrUrl;
        }

        public async Task<AccessTokenInfo> AdminLoginAsync(PasswordLoginValueObject value)
        {
            var userInfo = await PasswordLoginAsync(value);
            if (userInfo.Role == UserRole.Admin)
            {
                return CreateUserAccessToken(userInfo);
            }
            else
            {
                throw new AppException("帐号未授权");
            }
        }

        public async Task<long> SaveShippingAddressAsync(string userId, ShippingAddressInfo addressModel)
        {
            addressModel.UserId = userId;
            var addressInfos = await addressRepository.Select.Where(x => x.UserId == userId).ToListAsync();
            if (addressInfos == null && addressInfos.Count == 0)
            {
                addressModel.IsDefault = true;
            }
            else
            {
                if (addressModel.IsDefault)
                {
                    var addressInfo = addressInfos.FirstOrDefault(c => c.IsDefault);
                    if (addressInfo != null && addressInfo.Id != addressModel.Id && addressModel.Id > 0)
                    {
                        addressInfo.CancelDefault();
                        addressRepository.Insert(addressInfo);
                    }
                }
            }
            addressRepository.InsertOrUpdate(addressModel);
            return addressModel.Id;
        }

        public async Task RemoveShippingAddressAsync(string userId, long addressId)
        {
            var addresInfos = await addressRepository.Select.Where(x => x.UserId == userId).ToListAsync();
            var info = addresInfos.FirstOrDefault(c => c.Id == addressId);
            if (info != null)
            {
                addressRepository.Delete(info);
            }
        }
        //使用邀请码绑定推广关系
        public async Task BindInviteCode(string userId, string code)
        {
            var user = await userRepository.GetUserInfoAsync(userId);
            if (!string.IsNullOrWhiteSpace(user.InviteUserId))
            {
                throw new AppException("不能重复添加邀请");
            }

            //推广者
            var inviteUser = await userRepository.Select.Where(x => x.InviteCode == code).FirstAsync();
            if (inviteUser == null)
            {
                throw new AppException("邀请码无效");
            }
            if (inviteUser.UserId == userId)
            {
                throw new AppException("不能添加自己的邀请码");
            }
            if (inviteUser.InviteUserId == userId)
            {
                throw new AppException("不能相互邀请");
            }
            user.SetInviteUser(inviteUser.UserId);
            userRepository.Update(user);

            await mediator.Publish(new BindInviteEvent(user, inviteUser));
        }



        /// <summary>
        /// 更换用户等级
        /// 如果等级过期或未有等级，延期开始日期为当前日期
        /// 如果等级不过期，按等级到期那天为开始时间计算
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="grade"></param>
        /// <returns></returns>
        /// <exception cref="AppException"></exception>
        public async Task ChangeUserGradeAsync(string userId, UserGrade grade)
        {
            var user = await userRepository.GetUserInfoAsync(userId);
            if (user == null)
            {
                throw new AppException("无效用户");
            }

            DateTime currentDate = DateTime.Now;
            //UserGrade currentGrade = user.Grade;//当前用户等级
            //if(user.Grade== UserGrade.Member)
            //{
            //    //未升级VIP时
            //    currentGrade = grade;
            //}
            //if (user.VipEndDate != null)
            //{
            //    //未过期
            //    if (user.VipEndDate > DateTime.Now)
            //    {
            //        currentDate = (DateTime)user.VipEndDate;
            //    }else
            //    {
            //        //己过期
            //        currentGrade = grade;
            //    }
            //}
            DateTime expirseDate = DateTime.Now.AddYears(100);
            //周卡
            if (grade == UserGrade.VIP3)
            {
                expirseDate = currentDate.AddDays(7);
            }
            //月卡
            if (grade == UserGrade.VIP1)
            {
                expirseDate = currentDate.AddDays(30);
            }
            //年卡
            if (grade == UserGrade.VIP2)
            {
                expirseDate = currentDate.AddDays(365);
            }

            //终身
            if (grade == UserGrade.VIP5)
            {
                expirseDate = currentDate.AddYears(10);
            }

            //  user.ChangeGrade(grade, expirseDate);
            userRepository.Insert(user);
        }

        public async Task<UserInfo> ChangeAvatarAsync(ChangeUserInfo userInfo)
        {
            var user = await userRepository.GetUserInfoAsync(userInfo.UserId);
            if (user == null)
                throw new AppException("用户无效");


            user.ChangeNick(userInfo.Name);
            user.ChangeAvatar(userInfo.Avatar);
            userRepository.Update(user);
            return user;
        }

        public async Task ChangeSatusAsync(string userId,int status)
        {
			var user = await userRepository.GetUserInfoAsync(userId);
			if (user == null)
				throw new AppException("用户无效");

            user.ChangeStatus(status);

            userRepository.Update(user);
		}


    }
}
